#pragma once
#include <iostream>
#include "Connection.hpp"
#include "Log.hpp"
#include "Protocol.hpp"
#include "Calculate.hpp"

const static int buffer_size = 1024;

using namespace Protocol;
using namespace CalCulateNS;
class HandlerConnection
{
public:
    static void HandlerRequest(Connection *conn)
    {
        std::string &inbuffer = conn->InBuffer();
        std::string message;
        Factory factory;
        Calculate calculate;
        auto req = factory.BuildRequest();
        // 1.解决粘包问题，查看是否有一个完整的报文
        while (Decode(inbuffer, &message))
        {
            // 2.反序列化
            if (!req->Deserialize(message))
                continue;

            // 3.计算得到结果，构建响应报文
            auto resp = calculate.Cal(req);

            // 4.将响应报文进行序列化
            std::string responseStr;
            resp->Serializate(&responseStr);

            // 5.将序列化好的响应报文进行封装
            responseStr = Encode(responseStr);

            // 6.将封装好的响应报文追加到connection的发送缓冲区中
            conn->AddOutBuffer(responseStr);
        }

        // 开始数据发送了，当发送缓冲区不为空时，才能进行发送
        if (!conn->OutBufferEmpty())
            conn->_sender(conn);
    }

    static void Recver(Connection *conn)
    {
        errno = 0;

        char buffer[buffer_size];
        while (true)
        {
            ssize_t n = recv(conn->Sockfd(), buffer, sizeof(buffer) - 1, 0);
            // conn->sockfd()已经被设置为非阻塞了
            if (n > 0)
            {
                buffer[n] = 0;
                conn->AddInBuffer(buffer); // 将读取到的内容添加到connection的缓冲区中
            }
            else
            {
                if (errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    conn->_excepter(conn); // 交给异常处理函数处理
                    return;
                }
            }
        }
        // 处理数据
        HandlerRequest(conn);
    }
    static void Sender(Connection *conn)
    {
        errno = 0;
        while (true)
        {
            std::string &outbuffer = conn->OutBuffer();
            ssize_t n = send(conn->Sockfd(), outbuffer.c_str(), outbuffer.size(), 0);
            if (n >= 0)
            {
                outbuffer.erase(0, n);
                if (outbuffer.empty())
                    break;
            }
            else
            {
                if (errno == EAGAIN) // 这里就表示，内核中的发送缓冲区写满了，用户发送失败了
                    break;
                else if (errno == EINTR)
                    continue;
                else
                {
                    conn->_excepter(conn); // 交给异常处理函数处理
                    return;
                }
            }
        }

        // 走到这里，意味着本轮数据发满了，但是数据有可能还没有发完？因为内核中的发送缓冲区有可能被写满了
        // 开启对conn->Sockfd()的EPOLLOUT的关心
        if (!conn->OutBufferEmpty())
        {
            // 如果缓冲区还有内容，说明是发送缓冲区被写满了，我们要将写进行关心起来
            conn->_R->EnableReadWrite(conn->Sockfd(), true, true);
        }
        else
        {
            conn->_R->EnableReadWrite(conn->Sockfd(), true, false);
        }
    }
    static void Accepter(Connection *conn)
    {
        errno = 0;

        lg.LogMessage(Info, "remove a connection, who: %d\n", conn->Sockfd());
        // 在epoller取消对sockfd的关心
        // 在unordered_map中移除conn
        conn->_R->RemoveConnection(conn->Sockfd());
        // close sockfd
        conn->Close();
        // delete conn
        delete conn;
    }
};
